﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using MyCommon.Helper;
using MyCommon.HttpContextUser;
using MyIServices;
using MyModels;
using MyModels.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text.RegularExpressions;

namespace MyExtension.Authorizations
{
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        private readonly IAuthenticationSchemeProvider _schemes;
        private readonly IRoleModulePermissionService _roleModulePermissionService;
        private readonly ISysUserInfoServices _sysUserInfoServices;
        private readonly IHttpContextAccessor _accessor;
        private readonly IUser _user;

        public PermissionHandler(IAuthenticationSchemeProvider schemes,
            IRoleModulePermissionService roleModulePermissionService,
            ISysUserInfoServices sysUserInfoServices,
            IHttpContextAccessor accessor,IUser user)
        {
            _schemes = schemes;
            _roleModulePermissionService = roleModulePermissionService;
            _sysUserInfoServices = sysUserInfoServices;
            _accessor = accessor;
            _user = user;
        }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            var httpContext = _accessor.HttpContext;

            if (!httpContext.User.Identity.IsAuthenticated)
            {
                _user.MessageModel = new ApiResponse(StatusCode.CODE401, "用户不存在或已被删除").MessageModel;
                context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.message));
                return;
            }
            // 获取系统中所有的角色和菜单关系集合
            if (!requirement.Permissions.Any())
            {
                var data = await _roleModulePermissionService.RoleModuleMap();

                requirement.Permissions = data.Where(i => i.IsDeleted == false).OrderBy(i => i.Id)
                    .Select(i => new PermissionItem { Url = i.Modules.LinkUrl!, Role = i.Role.Name! })
                    .ToList();
            }

            if (httpContext != null) {
                var requestUrl = httpContext.Request.Path.Value?.ToLower();

                // 整体结构类似认证中间件UseAuthentication的逻辑，具体查看开源地址
                // https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/Core/src/AuthenticationMiddleware.cs
                httpContext.Features.Set<IAuthenticationFeature>(new AuthenticationFeature()
                {
                    OriginalPath = httpContext.Request.Path.Value,
                    OriginalPathBase = httpContext.Request.PathBase
                });

                //判断请求是否拥有凭证,判断是否登录
                var defaultAuthorizate = await _schemes.GetDefaultAuthenticateSchemeAsync();
                if (defaultAuthorizate != null) {
                    var result = await httpContext.AuthenticateAsync(defaultAuthorizate.Name);

                    httpContext.User = result.Principal!;

                    #region 校验用户
                    //应该要先校验用户的信息 再校验菜单权限相关的
                    // JWT模式下校验当前用户状态
                    SysUserInfo user = new();
                    //校验用户
                    user = await _sysUserInfoServices.QueryById(_user.UserId, false);
                    if (user == null)
                    {
                        _user.MessageModel = new ApiResponse(StatusCode.CODE401, "用户不存在或已被删除").MessageModel;
                        context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.message));
                        return;
                    }

                    if (user.IsDeleted.Value)
                    {
                        _user.MessageModel = new ApiResponse(StatusCode.CODE401, "用户已被删除,禁止登陆!").MessageModel;
                        context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.message));
                        return;
                    }

                    if (!user.Enabled)
                    {
                        _user.MessageModel = new ApiResponse(StatusCode.CODE401, "用户已被禁用!禁止登陆!").MessageModel;
                        context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.message));
                        return;
                    }
                    #endregion

                    // 判断token是否过期，过期则重新登录
                    var isExp = false;
                    var userExpirationValue = httpContext.User.Claims.FirstOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value;
                    if (userExpirationValue != null&& DateTime.Parse( userExpirationValue)>=DateTime.Now) { 
                        isExp = true;
                    }

                    if (!isExp)
                    {
                        context.Fail(new AuthorizationFailureReason(this, "授权已过期,请重新授权"));
                        return;
                    }

                    //校验签发时间
                    var value = httpContext.User.Claims
                                .FirstOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
                    if (value != null)
                    {
                        if (user.CriticalModifyTime > value.ObjToDate())
                        {
                            _user.MessageModel = new ApiResponse(StatusCode.CODE401, "很抱歉,授权已失效,请重新授权").MessageModel;
                            context.Fail(new AuthorizationFailureReason(this, _user.MessageModel.message));
                            return;
                        }
                    }

                    // 获取当前用户的角色信息
                    var currentUserRoles =  httpContext.User.Claims.Where(i=>i.Type==ClaimTypes.Role).Select(i=>i.Value).ToList();
                    if (!currentUserRoles.Any()) { 
                        currentUserRoles = httpContext.User.Claims.Where(i => i.Type == "role").Select(i => i.Value).ToList();
                    }

                    //超级管理员 默认拥有所有权限
                    if (currentUserRoles.All(s => s != "SuperAdmin"))
                    {
                        var isMatchRole = false;
                        var permissionRoles = requirement.Permissions.Where(i => currentUserRoles.Contains(i.Role));
                        foreach (var permissionRole in permissionRoles)
                        {
                            var match = Regex.Match(requestUrl, permissionRole.Url.ToLower());
                            if (match.Value == requestUrl)
                            {
                                isMatchRole = true;
                                break;
                            }
                        }

                        //验证权限
                        if (currentUserRoles.Count <= 0|| !isMatchRole) { 
                            context.Fail(); return;
                        }
                    }
                    context.Succeed(requirement);
                    return;
                }

                //判断没有登录时，是否访问登录的url,并且是Post请求，并且是form表单提交类型，否则为失败
                if (!(requestUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) &&
                      (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType)))
                {
                    context.Fail();
                    return;
                }

              //  context.Succeed(requirement);
            }
        }
    }
}
